iT邦幫忙

2022 iThome 鐵人賽

0
AI & Data

預測惱人的人事物:跟我一起學習如何用資料分析來避開他們系列 第 36

修復 bug:重複通知 & 附帶處理 Notifee 原生的循環通知

  • 分享至 

  • xImage
  •  

在觀察電池最佳化設定的問題是否被排除的同時,讓我們來解決通知重複的 bug 吧!

調查

筆者調查了官方文件,發現我們當初透過 createTriggerNotification 建立任務時,並沒有提供 id。

此外,如果有 id 已經通知排程了,則 createTriggerNotification 的效果會是 update 既有的 id,可以說這個 API 其實是 upsert 的行為。

若我們不提供 id,根據官方的文件是隨機 gen 出來的:

Defaults to a random string if not provided.

筆者亦發現有取得目前所有建立的通知任務 id 的 API: getTriggerNotificationIds

讓我們在 notification.js 中的 setNotificationByWeekDay 加入這段驗證一下:

const ids = await notifee.getTriggerNotificationIds();
console.log(ids.length);

要記得把 fuction 改成 async。

refresh app 幾次,印出來後我們可以看到:
https://ithelp.ithome.com.tw/upload/images/20221021/201413578wh2LYiDDW.png

固定以 14 筆的幅度在增長,符合我們先前的推斷

理由是, setNotificationByWeekDay 會在一週七天,分別建立早上以及晚上的通知:

 for (const predict of nightPrediction) {
    const {weekday, time} = predict;
    // night notification
    onCreateTriggerNotificationByWeekday(time, weekday);

    // morning notification
    onCreateTriggerNotificationByWeekday(dayPredcition, weekday);
  }

所以每次 app 刷新時, useEffect 內的 setNotificationByWeekDay 都會在既有的任務 list 中加入 14 筆通知排程。


實作

筆者決定加入通知 id,來讓每次 app 刷新只是 update 既有的任務,而非 create 新的任務。

決定 id 的形式

筆者希望簡單就好,快速決定是 $weekday-$nightorday 的格式。

首先我們在 onCreateTriggerNotificationByWeekday 中加入第三個參數 isNight,以及以下邏輯:

  const customizedNotificationId =
    isNight === undefined
      ? null
      : isNight
      ? `${weekday}-night`
      : `${weekday}-day`;

  onCreateTriggerNotification(
    absoluteTimeInMs,
    message,
    customizedNotificationId,
  );

例如以週二早上為例,我們 weekday 傳入的值是 tueisNight 傳入的是 false,就會組出 tue-day。同時也保有如果沒有傳入 isNight 時,就委由底層邏輯幫忙產出 id 的彈性。

我們將自製的 id 傳入真正 call notifee api 的 onCreateTriggerNotification 中。同時,我們在 setNotificationByWeekDay 加入第三個參數:

 for (const predict of nightPrediction) {
    const {weekday, time} = predict;
    // night notification
    onCreateTriggerNotificationByWeekday(time, weekday, true);

    // morning notification
    onCreateTriggerNotificationByWeekday(dayPredcition, weekday, false);
  }

進一步,同時筆者也實作了上層 function 沒有提供 id 時的備案,然而途中碰到一些問題,記錄如下:

uuid

筆者首先嘗試的是 uuid

id: id || uuidv4(),

但得到以下錯誤訊息:

crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported

找到了這篇討論:https://github.com/uuidjs/uuid/issues/416

快速瀏覽過去,心中有已想好備案,問題看似無法馬上排除,所以決定不用 uuid 套件。


nanoid

使用時,碰到以下問題:

ReferenceError: Property 'crypto' doesn't exist

怎麼都是 crypto 相關的,筆者決定有空再來調查亂數產生的 id。

由於目前沒有其他需求,只是要做到通知任務不重複以及管理通知而已,故筆者的 workaround 為使用 DateISOString

id: id || new Date().toISOString(),

最終底層的 id 就會是客製化後傳入的,不然就是直接使用 Date ISOString 來作為 ID。

export async function onCreateTriggerNotification(
  time: String,
  message: String,
  id: String | null,
) {
   ...
   // Create a trigger notification
  await notifee.createTriggerNotification(
    {
      id: id || new Date().toISOString(),
      title: '關門通知',
      body: message || '樓下關門即將在 10 分鐘內發生',
      android: {
        channelId,
        pressAction: {
          id: 'default',
        },
      },
    },
    trigger,
  );
 }

成果

https://ithelp.ithome.com.tw/upload/images/20221021/20141357ZqH0Vh1ocL.png

幾次刷新後,任務數目仍然維持一樣的,可以看到 notifee 幫忙產生的 id、實作過程中以日期產生的 id 以及我們客製的 id 同時共存。

https://ithelp.ithome.com.tw/upload/images/20221021/20141357XFGal05JR4.png

bug 解決!


附帶處理:Notifee 本身就有定期通知的 API

筆者先前沒發現文件有提及循環通知

我們可以在 trigger 加入循環通知週期 (repeatFrequency):

const trigger: TimestampTrigger = {
  type: TriggerType.TIMESTAMP,
  timestamp: time,
  repeatFrequency: RepeatFrequency.WEEKLY,
};

筆者決定以此實作,並刪除原先 useEffect 中設定循環通知的段落:

// trigger every 7 days
setInterval(setNotificationByWeekDay, sevenDaysInterval);

初步看下來這個 bug 算是解決了,而且還優化了循環通知邏輯,讓我們使用幾天驗證一下吧!

今天收工!


上一篇
修復 bug:電池最佳化無法取消 (part 1 of 2)
下一篇
修復 bug:電池最佳化無法取消 (part 2 of 2)
系列文
預測惱人的人事物:跟我一起學習如何用資料分析來避開他們38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言